/*
	YoghurtGum - 2D Game Engine

	Copyright 2009-2011 Quinten Lansu
	
	Licensed under the Apache License, Version 2.0 (the "License"); you may not 
	use this file except in compliance with the License. You may obtain a copy 
	of the License at 
		
		http://www.apache.org/licenses/LICENSE-2.0 
		
	Unless required by applicable law or agreed to in writing, software 
	distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
	WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
	License for the specific language governing permissions and limitations 
	under the License. 
*/

#ifndef _COLOR_H_
#define _COLOR_H_

#include "YGSettings.h"
#include "YGGeneralMath.h"

namespace YoghurtGum
{

#if (YG_COLOR_DEPTH == YG_COLOR_DEPTH_A8R8G8B8)

	typedef YG_COLOR_TYPE_A8R8G8B8         YGC;

	static const YGC YG_COLOR_SHIFT =      YG_COLOR_TYPE_A8R8G8B8_SHIFT;
	static const YGC YG_COLOR_SHIFT_A =    YG_COLOR_TYPE_A8R8G8B8_SHIFT_A;
	static const YGC YG_COLOR_SHIFT_R =    YG_COLOR_TYPE_A8R8G8B8_SHIFT_R;
	static const YGC YG_COLOR_SHIFT_G =    YG_COLOR_TYPE_A8R8G8B8_SHIFT_G;
	static const YGC YG_COLOR_SHIFT_B =    YG_COLOR_TYPE_A8R8G8B8_SHIFT_B;

	static const YGC YG_COLOR_BITMASK_R =  YG_COLOR_TYPE_A8R8G8B8_BITMASK_R;
	static const YGC YG_COLOR_BITMASK_G =  YG_COLOR_TYPE_A8R8G8B8_BITMASK_G;
	static const YGC YG_COLOR_BITMASK_B =  YG_COLOR_TYPE_A8R8G8B8_BITMASK_B;

	static const YGC YG_COLOR_MASK_A =     YG_COLOR_TYPE_A8R8G8B8_MASK_A;
	static const YGC YG_COLOR_MASK_C =     YG_COLOR_TYPE_A8R8G8B8_MASK_C;
	static const YGC YG_COLOR_MASK_R =     YG_COLOR_TYPE_A8R8G8B8_MASK_R;
	static const YGC YG_COLOR_MASK_G =     YG_COLOR_TYPE_A8R8G8B8_MASK_G;
	static const YGC YG_COLOR_MASK_B =     YG_COLOR_TYPE_A8R8G8B8_MASK_B;
	static const YGC YG_COLOR_MASK_RB =    YG_COLOR_TYPE_A8R8G8B8_MASK_RB;
	static const YGC YG_COLOR_MASK_AG =    YG_COLOR_TYPE_A8R8G8B8_MASK_AG;

#elif (YG_COLOR_DEPTH == YG_COLOR_DEPTH_A8B8G8R8)

	typedef YG_COLOR_TYPE_A8B8G8R8         YGC;

	static const YGC YG_COLOR_SHIFT =      YG_COLOR_TYPE_A8B8G8R8_SHIFT;
	static const YGC YG_COLOR_SHIFT_A =    YG_COLOR_TYPE_A8B8G8R8_SHIFT_A;
	static const YGC YG_COLOR_SHIFT_R =    YG_COLOR_TYPE_A8B8G8R8_SHIFT_R;
	static const YGC YG_COLOR_SHIFT_G =    YG_COLOR_TYPE_A8B8G8R8_SHIFT_G;
	static const YGC YG_COLOR_SHIFT_B =    YG_COLOR_TYPE_A8B8G8R8_SHIFT_B;

	static const YGC YG_COLOR_BITMASK_R =  YG_COLOR_TYPE_A8B8G8R8_BITMASK_R;
	static const YGC YG_COLOR_BITMASK_G =  YG_COLOR_TYPE_A8B8G8R8_BITMASK_G;
	static const YGC YG_COLOR_BITMASK_B =  YG_COLOR_TYPE_A8B8G8R8_BITMASK_B;

	static const YGC YG_COLOR_MASK_A =     YG_COLOR_TYPE_A8B8G8R8_MASK_A;
	static const YGC YG_COLOR_MASK_C =     YG_COLOR_TYPE_A8B8G8R8_MASK_C;
	static const YGC YG_COLOR_MASK_R =     YG_COLOR_TYPE_A8B8G8R8_MASK_R;
	static const YGC YG_COLOR_MASK_G =     YG_COLOR_TYPE_A8B8G8R8_MASK_G;
	static const YGC YG_COLOR_MASK_B =     YG_COLOR_TYPE_A8B8G8R8_MASK_B;
	static const YGC YG_COLOR_MASK_RB =    YG_COLOR_TYPE_A8B8G8R8_MASK_RB;
	static const YGC YG_COLOR_MASK_AG =    YG_COLOR_TYPE_A8B8G8R8_MASK_AG;


#elif (YG_COLOR_DEPTH == YG_COLOR_DEPTH_R8G8B8)

	typedef YG_COLOR_TYPE_R8G8B8           YGC;

	static const YGC YG_COLOR_SHIFT =      YG_COLOR_TYPE_R8G8B8_SHIFT;
	static const YGC YG_COLOR_SHIFT_A =    YG_COLOR_TYPE_R8G8B8_SHIFT_A;
	static const YGC YG_COLOR_SHIFT_R =    YG_COLOR_TYPE_R8G8B8_SHIFT_R;
	static const YGC YG_COLOR_SHIFT_G =    YG_COLOR_TYPE_R8G8B8_SHIFT_G;
	static const YGC YG_COLOR_SHIFT_B =    YG_COLOR_TYPE_R8G8B8_SHIFT_B;

	static const YGC YG_COLOR_BITMASK_R =  YG_COLOR_TYPE_R8G8B8_BITMASK_R;
	static const YGC YG_COLOR_BITMASK_G =  YG_COLOR_TYPE_R8G8B8_BITMASK_G;
	static const YGC YG_COLOR_BITMASK_B =  YG_COLOR_TYPE_R8G8B8_BITMASK_B;

	static const YGC YG_COLOR_MASK_A =     YG_COLOR_TYPE_R8G8B8_MASK_A;
	static const YGC YG_COLOR_MASK_C =     YG_COLOR_TYPE_R8G8B8_MASK_C;
	static const YGC YG_COLOR_MASK_R =     YG_COLOR_TYPE_R8G8B8_MASK_R;
	static const YGC YG_COLOR_MASK_G =     YG_COLOR_TYPE_R8G8B8_MASK_G;
	static const YGC YG_COLOR_MASK_B =     YG_COLOR_TYPE_R8G8B8_MASK_B;
	static const YGC YG_COLOR_MASK_RB =    YG_COLOR_TYPE_R8G8B8_MASK_RB;
	static const YGC YG_COLOR_MASK_AG =    YG_COLOR_TYPE_R8G8B8_MASK_AG;

#elif (YG_COLOR_DEPTH == YG_COLOR_DEPTH_R5G6B5)

	typedef YG_COLOR_TYPE_R5G6B5           YGC;

	static const YGC YG_COLOR_SHIFT =      YG_COLOR_TYPE_R5G6B5_SHIFT;
	static const YGC YG_COLOR_SHIFT_A =    YG_COLOR_TYPE_R5G6B5_SHIFT_A;
	static const YGC YG_COLOR_SHIFT_R =    YG_COLOR_TYPE_R5G6B5_SHIFT_R;
	static const YGC YG_COLOR_SHIFT_G =    YG_COLOR_TYPE_R5G6B5_SHIFT_G;
	static const YGC YG_COLOR_SHIFT_B =    YG_COLOR_TYPE_R5G6B5_SHIFT_B;

	static const YGC YG_COLOR_BITMASK_R =  YG_COLOR_TYPE_R5G6B5_BITMASK_R;
	static const YGC YG_COLOR_BITMASK_G =  YG_COLOR_TYPE_R5G6B5_BITMASK_G;
	static const YGC YG_COLOR_BITMASK_B =  YG_COLOR_TYPE_R5G6B5_BITMASK_B;

	static const YGC YG_COLOR_MASK_A =     YG_COLOR_TYPE_R5G6B5_MASK_A;
	static const YGC YG_COLOR_MASK_C =     YG_COLOR_TYPE_R5G6B5_MASK_C;
	static const YGC YG_COLOR_MASK_R =     YG_COLOR_TYPE_R5G6B5_MASK_R;
	static const YGC YG_COLOR_MASK_G =     YG_COLOR_TYPE_R5G6B5_MASK_G;
	static const YGC YG_COLOR_MASK_B =     YG_COLOR_TYPE_R5G6B5_MASK_B;
	static const YGC YG_COLOR_MASK_RB =    YG_COLOR_TYPE_R5G6B5_MASK_RB;
	static const YGC YG_COLOR_MASK_AG =    YG_COLOR_TYPE_R5G6B5_MASK_AG;

#endif

	static const float YG_COLOR_BITMASK_FR = (float)YG_COLOR_BITMASK_R;
	static const float YG_COLOR_BITMASK_FG = (float)YG_COLOR_BITMASK_G;
	static const float YG_COLOR_BITMASK_FB = (float)YG_COLOR_BITMASK_B;

	static const float YG_COLOR_SHIFT_FR   = (float)YG_COLOR_SHIFT_R;
	static const float YG_COLOR_SHIFT_FG   = (float)YG_COLOR_SHIFT_G;
	static const float YG_COLOR_SHIFT_FB   = (float)YG_COLOR_SHIFT_B;

	typedef unsigned long Pixel;

	// =========================================
	// Make
	// =========================================

#if (YG_COLOR_DEPTH == YG_COLOR_DEPTH_A8R8G8B8)

	static YGC PixelMake(unsigned char a_Red, unsigned char a_Green, unsigned a_Blue)
	{
		return (
			((a_Red   << YG_COLOR_SHIFT_R) & YG_COLOR_MASK_R) |
			((a_Green << YG_COLOR_SHIFT_G) & YG_COLOR_MASK_G) |
			((a_Blue  << YG_COLOR_SHIFT_B) & YG_COLOR_MASK_B)
		);
	}

	static YGC PixelMake(unsigned char a_Red, unsigned char a_Green, unsigned a_Blue, unsigned char a_Alpha)
	{
		return (
			((a_Alpha << YG_COLOR_SHIFT_A) & YG_COLOR_MASK_A) |
			((a_Red   << YG_COLOR_SHIFT_R) & YG_COLOR_MASK_R) |
			((a_Green << YG_COLOR_SHIFT_G) & YG_COLOR_MASK_G) |
			((a_Blue  << YG_COLOR_SHIFT_B) & YG_COLOR_MASK_B)
		);
	}

#elif (YG_COLOR_DEPTH == YG_COLOR_DEPTH_A8B8G8R8)

	static YGC PixelMake(unsigned char a_Red, unsigned char a_Green, unsigned a_Blue)
	{
		return (
			((a_Red   << YG_COLOR_SHIFT_R) & YG_COLOR_MASK_R) |
			((a_Green << YG_COLOR_SHIFT_G) & YG_COLOR_MASK_G) |
			((a_Blue  << YG_COLOR_SHIFT_B) & YG_COLOR_MASK_B)
		);
	}

	static YGC PixelMake(unsigned char a_Red, unsigned char a_Green, unsigned a_Blue, unsigned char a_Alpha)
	{
		return (
			((a_Alpha << YG_COLOR_SHIFT_A) & YG_COLOR_MASK_A) |
			((a_Red   << YG_COLOR_SHIFT_R) & YG_COLOR_MASK_R) |
			((a_Green << YG_COLOR_SHIFT_G) & YG_COLOR_MASK_G) |
			((a_Blue  << YG_COLOR_SHIFT_B) & YG_COLOR_MASK_B)
		);
	}

#elif (YG_COLOR_DEPTH == YG_COLOR_DEPTH_R8G8B8)

	static YGC PixelMake(unsigned char a_Red, unsigned char a_Green, unsigned a_Blue)
	{
		return (
			((a_Red   << YG_COLOR_SHIFT_R) & YG_COLOR_MASK_R) |
			((a_Green << YG_COLOR_SHIFT_G) & YG_COLOR_MASK_G) |
			((a_Blue  << YG_COLOR_SHIFT_B) & YG_COLOR_MASK_B)
		);
	}

	static YGC PixelMake(unsigned char a_Red, unsigned char a_Green, unsigned a_Blue, unsigned char a_Alpha)
	{
		return (
			((a_Red   << YG_COLOR_SHIFT_R) & YG_COLOR_MASK_R) |
			((a_Green << YG_COLOR_SHIFT_G) & YG_COLOR_MASK_G) |
			((a_Blue  << YG_COLOR_SHIFT_B) & YG_COLOR_MASK_B)
		);
	}

#elif (YG_COLOR_DEPTH == YG_COLOR_DEPTH_R5G6B5)

	static YGC PixelMake(unsigned char a_Red, unsigned char a_Green, unsigned a_Blue)
	{
		return (
			(((a_Red   * YG_COLOR_MASK_R) >> 8) & YG_COLOR_MASK_R) |
			(((a_Green * YG_COLOR_MASK_G) >> 8) & YG_COLOR_MASK_G) |
			(((a_Blue  * YG_COLOR_MASK_B) >> 8) & YG_COLOR_MASK_B)
		);
	}

	static YGC PixelMake(unsigned char a_Red, unsigned char a_Green, unsigned a_Blue, unsigned char a_Alpha)
	{
		return (
			(((a_Red   * YG_COLOR_MASK_R) >> 8) & YG_COLOR_MASK_R) |
			(((a_Green * YG_COLOR_MASK_G) >> 7) & YG_COLOR_MASK_G) |
			(((a_Blue  * YG_COLOR_MASK_B) >> 8) & YG_COLOR_MASK_B)
		);
	}

#endif

#if (YG_OS_TYPE == YG_OS_TYPE_WINDOWSMOBILE)

	static uint32 PixelMakeD3DM(uint8 a_Red, uint8 a_Green, uint8 a_Blue)
	{
		return (
			0xFF000000 | 
			((a_Red   << 16) & 0xFF0000) |
			((a_Green << 8 ) & 0x00FF00) |
			((a_Blue       ) & 0x0000FF)
		);
	}

#endif

	// =========================================
	// Getters
	// =========================================

	static YGC PixelGetRedComponent(YGC a_Color)    
	{ 
		return ((a_Color >> YG_COLOR_SHIFT_R) & YG_COLOR_MASK_R);
	}
	static YGC PixelGetGreenComponent(YGC a_Color)  
	{ 
		return ((a_Color >> YG_COLOR_SHIFT_G) & YG_COLOR_MASK_G); 
	}
	static YGC PixelGetBlueComponent(YGC a_Color)   
	{ 
		return ((a_Color >> YG_COLOR_SHIFT_B) & YG_COLOR_MASK_B);
	}

#if (YG_COLOR_DEPTH == YG_COLOR_DEPTH_A8R8G8B8)

	static YGC PixelGetRed(YGC a_Color)             
	{ 
		return ((a_Color >> YG_COLOR_SHIFT_R) & YG_COLOR_BITMASK_R); 
	}
	static YGC PixelGetGreen(YGC a_Color)           
	{ 
		return ((a_Color >> YG_COLOR_SHIFT_G) & YG_COLOR_BITMASK_G); 
	}
	static YGC PixelGetBlue(YGC a_Color)            
	{ 
		return ((a_Color >> YG_COLOR_SHIFT_B) & YG_COLOR_BITMASK_B); 
	}

#elif (YG_COLOR_DEPTH == YG_COLOR_DEPTH_R8G8B8)

	static YGC PixelGetRed(YGC a_Color)             
	{ 
		return ((a_Color >> YG_COLOR_SHIFT_R) & YG_COLOR_BITMASK_R); 
	}
	static YGC PixelGetGreen(YGC a_Color)           
	{ 
		return ((a_Color >> YG_COLOR_SHIFT_G) & YG_COLOR_BITMASK_G); 
	}
	static YGC PixelGetBlue(YGC a_Color)            
	{ 
		return ((a_Color >> YG_COLOR_SHIFT_B) & YG_COLOR_BITMASK_B); 
	}

#elif (YG_COLOR_DEPTH == YG_COLOR_DEPTH_R5G6B5)

	static YGC PixelGetRed(YGC a_Color)             
	{ 
		return ((((a_Color & YG_COLOR_MASK_R) >> YG_COLOR_SHIFT_R) << 8) / YG_COLOR_BITMASK_R);
	}
	static YGC PixelGetGreen(YGC a_Color)           
	{ 
		return ((((a_Color & YG_COLOR_MASK_G) >> YG_COLOR_SHIFT_G) << 7) / YG_COLOR_BITMASK_G);
	}
	static YGC PixelGetBlue(YGC a_Color)            
	{ 
		return ((((a_Color & YG_COLOR_MASK_B) >> YG_COLOR_SHIFT_B) << 8) / YG_COLOR_BITMASK_B);
	}

#endif

	static float PixelGetRedRatio(YGC a_Color)
	{
		return ((float)((a_Color >> YG_COLOR_SHIFT_R) & YG_COLOR_BITMASK_R) / YG_COLOR_BITMASK_FR);
	}
	static float PixelGetGreenRatio(YGC a_Color)
	{
		return ((float)((a_Color >> YG_COLOR_SHIFT_G) & YG_COLOR_BITMASK_G) / YG_COLOR_BITMASK_FG);
	}
	static float PixelGetBlueRatio(YGC a_Color)
	{
		return ((float)((a_Color >> YG_COLOR_SHIFT_B) & YG_COLOR_BITMASK_B) / YG_COLOR_BITMASK_FB);
	}

	// =========================================
	// Blending
	// =========================================

	static YGC PixelBlend(YGC a_Left, YGC a_Right, unsigned char a_Amount)
	{
		const YGC Arb = a_Left & YG_COLOR_MASK_RB;
		const YGC Ag  = a_Left & YG_COLOR_MASK_G;

		const YGC RB = YG_COLOR_MASK_RB & (Arb + ((((a_Right & YG_COLOR_MASK_RB) - Arb) * a_Amount) >> YG_COLOR_SHIFT));
		const YGC G = YG_COLOR_MASK_G & (Ag + ((((a_Right & YG_COLOR_MASK_G) - Ag) * a_Amount) >> YG_COLOR_SHIFT));

		return (RB | G | YG_COLOR_MASK_A);
	}

	// =========================================
	// Operations
	// =========================================

#if (YG_COLOR_DEPTH == YG_COLOR_DEPTH_A8R8G8B8)

	static YGC PixelAdd(YGC a_Left, YGC a_Right)
	{
		YGC a  = ((a_Left & YG_COLOR_MASK_A)  + (a_Right & YG_COLOR_MASK_A))  & YG_COLOR_MASK_A;
		YGC rb = ((a_Left & YG_COLOR_MASK_RB) + (a_Right & YG_COLOR_MASK_RB)) & YG_COLOR_MASK_RB;
		YGC g  = ((a_Left & YG_COLOR_MASK_G)  + (a_Right & YG_COLOR_MASK_G))  & YG_COLOR_MASK_G;

		return (a + rb + g);
	}

#elif (YG_COLOR_DEPTH == YG_COLOR_DEPTH_R8G8B8)

	static YGC PixelAdd(YGC a_Left, YGC a_Right)
	{
		YGC rb = ((a_Left & YG_COLOR_MASK_RB) + (a_Right & YG_COLOR_MASK_RB)) & YG_COLOR_MASK_RB;
		YGC g  = ((a_Left & YG_COLOR_MASK_G)  + (a_Right & YG_COLOR_MASK_G))  & YG_COLOR_MASK_G;

		return (rb + g);
	}

#elif (YG_COLOR_DEPTH == YG_COLOR_DEPTH_R5G6B5)

	static YGC PixelAdd(YGC a_Left, YGC a_Right)
	{
		YGC rb = ((a_Left & YG_COLOR_MASK_RB) + (a_Right & YG_COLOR_MASK_RB)) & YG_COLOR_MASK_RB;
		YGC g  = ((a_Left & YG_COLOR_MASK_G)  + (a_Right & YG_COLOR_MASK_G))  & YG_COLOR_MASK_G;

		return (rb + g);
	}

#endif

	// =========================================
	// Conversions
	// =========================================

#if (YG_COLOR_DEPTH == YG_COLOR_DEPTH_A8R8G8B8)

	static YGC PixelConvert_ARGB_RGBA(YGC a_Color)
	{
		YGC a   = (a_Color & YG_COLOR_MASK_A) >> YG_COLOR_SHIFT_A;
		YGC rgb = (a_Color & YG_COLOR_MASK_C) << YG_COLOR_SHIFT;
		return (rgb + a);
	}

	static YGC PixelConvert_ARGB_ABGR(YGC a_Color)
	{
		YGC ag = (a_Color & YG_COLOR_MASK_AG);
		YGC r = (a_Color & YG_COLOR_MASK_R) >> YG_COLOR_SHIFT_R;
		YGC b = (a_Color & YG_COLOR_MASK_B) << YG_COLOR_SHIFT_R;

		return (ag + b + r);
	}

#endif

	static YGC PixelConvert_RGB_BGR(YGC a_Color)
	{
		YGC g = (a_Color & YG_COLOR_MASK_G);
		YGC r = (a_Color & YG_COLOR_MASK_R) >> YG_COLOR_SHIFT_R;
		YGC b = (a_Color & YG_COLOR_MASK_B) << YG_COLOR_SHIFT_R;

		return (b + g + r);
	}

#if (YG_OS_TYPE == YG_OS_TYPE_WINDOWSMOBILE)

	static unsigned long PixelConvert_YGC_D3DMCOLOR(YG_COLOR_TYPE_A8R8G8B8 a_Color)
	{
		return (a_Color);
	}

	static unsigned long PixelConvert_YGC_D3DMCOLOR(YG_COLOR_TYPE_R5G6B5 a_Color)
	{
		const unsigned long r =  ((((a_Color & YG_COLOR_TYPE_R5G6B5_MASK_R) >> YG_COLOR_TYPE_R5G6B5_SHIFT_R) << 8) / YG_COLOR_TYPE_R5G6B5_BITMASK_R) << 16;
		const unsigned long g =  ((((a_Color & YG_COLOR_TYPE_R5G6B5_MASK_G) >> YG_COLOR_TYPE_R5G6B5_SHIFT_G) << 7) / YG_COLOR_TYPE_R5G6B5_BITMASK_G) << 8;
		const unsigned long b =  ((((a_Color & YG_COLOR_TYPE_R5G6B5_MASK_B) >> YG_COLOR_TYPE_R5G6B5_SHIFT_B) << 8) / YG_COLOR_TYPE_R5G6B5_BITMASK_B);

		return (0xFF000000 | r | g | b);
	}

	static unsigned long PixelConvert_YGC_DDCOLOR(YG_COLOR_TYPE_A8R8G8B8 a_Color)
	{
		return (a_Color);
	}

	static unsigned long PixelConvert_YGC_DDCOLOR(YG_COLOR_TYPE_R5G6B5 a_Color)
	{
		const unsigned long r = ((((a_Color & YG_COLOR_TYPE_R5G6B5_MASK_R) >> YG_COLOR_TYPE_R5G6B5_SHIFT_R) << 8) / YG_COLOR_TYPE_R5G6B5_BITMASK_R) << YG_COLOR_TYPE_A8R8G8B8_SHIFT_R;
		const unsigned long g = ((((a_Color & YG_COLOR_TYPE_R5G6B5_MASK_G) >> YG_COLOR_TYPE_R5G6B5_SHIFT_G) << 7) / YG_COLOR_TYPE_R5G6B5_BITMASK_G) << YG_COLOR_TYPE_A8R8G8B8_SHIFT_G;
		const unsigned long b = ((((a_Color & YG_COLOR_TYPE_R5G6B5_MASK_B) >> YG_COLOR_TYPE_R5G6B5_SHIFT_B) << 8) / YG_COLOR_TYPE_R5G6B5_BITMASK_B) << YG_COLOR_TYPE_A8R8G8B8_SHIFT_B;

		/*const unsigned long r =  ((((a_Color & YG_COLOR_TYPE_R5G6B5_MASK_R) >> YG_COLOR_TYPE_R5G6B5_SHIFT_R) << 8) / YG_COLOR_TYPE_R5G6B5_BITMASK_R) << 16;
		const unsigned long g =  ((((a_Color & YG_COLOR_TYPE_R5G6B5_MASK_G) >> YG_COLOR_TYPE_R5G6B5_SHIFT_G) << 7) / YG_COLOR_TYPE_R5G6B5_BITMASK_G) << 8;
		const unsigned long b =  ((((a_Color & YG_COLOR_TYPE_R5G6B5_MASK_B) >> YG_COLOR_TYPE_R5G6B5_SHIFT_B) << 8) / YG_COLOR_TYPE_R5G6B5_BITMASK_B);*/

		return (0xFF000000 | r | g | b);
	}

#endif

	// =========================================
	// R8G8B8
	// =========================================

	static YG_COLOR_TYPE_R5G6B5 PixelConvert_R8G8B8_R5G6B5(YG_COLOR_TYPE_R8G8B8 a_Color)
	{
		YG_COLOR_TYPE_R5G6B5 r = 
			((a_Color & YG_COLOR_TYPE_R8G8B8_MASK_R) >> YG_COLOR_TYPE_R8G8B8_SHIFT_R) << YG_COLOR_TYPE_R5G6B5_SHIFT_R;
		YG_COLOR_TYPE_R5G6B5 g = 
			((a_Color & YG_COLOR_TYPE_R8G8B8_MASK_G) >> YG_COLOR_TYPE_R8G8B8_SHIFT_G) << YG_COLOR_TYPE_R5G6B5_SHIFT_G;
		YG_COLOR_TYPE_R5G6B5 b = 
			((a_Color & YG_COLOR_TYPE_R8G8B8_MASK_B) >> YG_COLOR_TYPE_R8G8B8_SHIFT_B) << YG_COLOR_TYPE_R5G6B5_SHIFT_B;

		return (r + g + b);
	}

	static YG_COLOR_TYPE_A8R8G8B8 PixelConvert_R8G8B8_A8R8G8B8(YG_COLOR_TYPE_R8G8B8 a_Color)
	{
		return (a_Color);
	}

	// =========================================
	// A8R8G8B8
	// =========================================

	static YG_COLOR_TYPE_R5G6B5 PixelConvert_A8R8G8B8_R5G6B5(YG_COLOR_TYPE_A8R8G8B8 a_Color)
	{
		YG_COLOR_TYPE_R5G6B5 r = 
			((a_Color & YG_COLOR_TYPE_A8R8G8B8_MASK_R) >> YG_COLOR_TYPE_A8R8G8B8_SHIFT_R) << YG_COLOR_TYPE_R5G6B5_SHIFT_R;
		YG_COLOR_TYPE_R5G6B5 g = 
			((a_Color & YG_COLOR_TYPE_A8R8G8B8_MASK_G) >> YG_COLOR_TYPE_A8R8G8B8_SHIFT_G) << YG_COLOR_TYPE_R5G6B5_SHIFT_G;
		YG_COLOR_TYPE_R5G6B5 b = 
			((a_Color & YG_COLOR_TYPE_A8R8G8B8_MASK_B) >> YG_COLOR_TYPE_A8R8G8B8_SHIFT_B) << YG_COLOR_TYPE_R5G6B5_SHIFT_B;

		return (r + g + b);
	}

	static YG_COLOR_TYPE_R8G8B8 PixelConvert_A8R8G8B8_R8G8B8(YG_COLOR_TYPE_A8R8G8B8 a_Color)
	{
		return (a_Color & YG_COLOR_MASK_C);
	}

	// =========================================
	// R5G6B5
	// =========================================

	static YG_COLOR_TYPE_R8G8B8 PixelConvert_R5G6B5_R8G8B8(YG_COLOR_TYPE_R5G6B5 a_Color)
	{
		YG_COLOR_TYPE_R8G8B8 r = 
			((((a_Color & YG_COLOR_MASK_R) >> YG_COLOR_SHIFT_R) << 8) / YG_COLOR_BITMASK_R) << YG_COLOR_TYPE_R8G8B8_SHIFT_R;
		YG_COLOR_TYPE_R8G8B8 g = 
			((((a_Color & YG_COLOR_MASK_G) >> YG_COLOR_SHIFT_G) << 7) / YG_COLOR_BITMASK_G) << YG_COLOR_TYPE_R8G8B8_SHIFT_G;
		YG_COLOR_TYPE_R8G8B8 b = 
			((((a_Color & YG_COLOR_MASK_B) >> YG_COLOR_SHIFT_B) << 8) / YG_COLOR_BITMASK_B) << YG_COLOR_TYPE_R8G8B8_SHIFT_B;

		return (r + g + b);
	}

	static YG_COLOR_TYPE_R8G8B8 PixelConvert_R5G6B5_A8R8G8B8(YG_COLOR_TYPE_R5G6B5 a_Color)
	{
		YG_COLOR_TYPE_A8R8G8B8 r = 
			((((a_Color & YG_COLOR_MASK_R) >> YG_COLOR_SHIFT_R) << 8) / YG_COLOR_BITMASK_R) << YG_COLOR_TYPE_A8R8G8B8_SHIFT_R;
		YG_COLOR_TYPE_A8R8G8B8 g = 
			((((a_Color & YG_COLOR_MASK_G) >> YG_COLOR_SHIFT_G) << 7) / YG_COLOR_BITMASK_G) << YG_COLOR_TYPE_A8R8G8B8_SHIFT_G;
		YG_COLOR_TYPE_A8R8G8B8 b = 
			((((a_Color & YG_COLOR_MASK_B) >> YG_COLOR_SHIFT_B) << 8) / YG_COLOR_BITMASK_B) << YG_COLOR_TYPE_A8R8G8B8_SHIFT_B;

		return (r + g + b);
	}

	// =========================================
	// Constants
	// =========================================

	static const YGC YGC_BLACK  = PixelMake(0,   0,   0  );
	static const YGC YGC_WHITE  = PixelMake(255, 255, 255);
	static const YGC YGC_GRAY   = PixelMake(127, 127, 127);
	static const YGC YGC_RED    = PixelMake(255, 0,   0  );
	static const YGC YGC_GREEN  = PixelMake(0,   255, 0  );
	static const YGC YGC_BLUE   = PixelMake(0,   0,   255);
	static const YGC YGC_PURPLE = PixelMake(255, 0,   255);

	class Color
	{

	public:

		// Constructors

		Color()
		{
			r = g = b = 0.f;
		}
		Color(float a_RGB)
		{
			r = g = b = a_RGB;
		}
		Color(float a_R, float a_G, float a_B)
		{
			r = a_R;
			g = a_G;
			b = a_B;
		}
		Color(YGC a_Color)
		{
			r = PixelGetRedRatio(a_Color);
			g = PixelGetGreenRatio(a_Color);
			b = PixelGetBlueRatio(a_Color);

			/*r = (float)((a_Color & YG_COLOR_MASK_R) >> YG_COLOR_SHIFT_R) / 255.f;
			g = (float)((a_Color & YG_COLOR_MASK_G) >> YG_COLOR_SHIFT_G) / 255.f;
			b = (float)((a_Color & YG_COLOR_MASK_B) >> YG_COLOR_SHIFT_B) / 255.f;*/
		}

		// Public methods

		inline Color& Clear()
		{
			r = g = b = 0.f;
			return *this;
		}
		
		/*inline YGC GetColor()
		{
			return
			(
				((unsigned long)(r * 255.f) << YG_SHIFT_RED		) +
				((unsigned long)(g * 255.f) << YG_SHIFT_GREEN	) +
				((unsigned long)(b * 255.f) << YG_SHIFT_BLUE	)
			);
		}*/

		inline YGC GetColor()
		{
			YGC result = PixelMake(
				(r > 1.f) ? 255 : (r < 0.f) ? 0 : (unsigned char)(r * 255.f),
				(g > 1.f) ? 255 : (g < 0.f) ? 0 : (unsigned char)(g * 255.f),
				(b > 1.f) ? 255 : (b < 0.f) ? 0 : (unsigned char)(b * 255.f)
			);

			return result;
		}

		inline unsigned long GetColorA8R8G8B8()
		{
			unsigned long R = 
				(r > 1.f) ? YG_COLOR_TYPE_A8R8G8B8_BITMASK_R : 
				(r < 0.f) ? 0x0000000 : 
				(unsigned long)(r * (float)YG_COLOR_TYPE_A8R8G8B8_BITMASK_R) << YG_COLOR_TYPE_A8R8G8B8_SHIFT_R;

			unsigned long G = 
				(g > 1.f) ? YG_COLOR_TYPE_A8R8G8B8_BITMASK_G : 
				(g < 0.f) ? 0x0000000 : 
				(unsigned long)(g * (float)YG_COLOR_TYPE_A8R8G8B8_BITMASK_G) << YG_COLOR_TYPE_A8R8G8B8_SHIFT_G;

			unsigned long B = 
				(b > 1.f) ? YG_COLOR_TYPE_A8R8G8B8_BITMASK_B : 
				(b < 0.f) ? 0x0000000 : 
				(unsigned long)(b * (float)YG_COLOR_TYPE_A8R8G8B8_BITMASK_B) << YG_COLOR_TYPE_A8R8G8B8_SHIFT_B;

			uint32 rgb = 0xFF000000 | R | G | B;

			return (rgb);
		}

		inline unsigned long GetColorCOLORREF()
		{
			unsigned long R = 
				(r > 1.f) ? 0x000000FF : 
				(r < 0.f) ? 0x00000000 : 
				(unsigned long)(r * 255.f);

			unsigned long G = 
				(g > 1.f) ? 0x0000FF00 : 
				(g < 0.f) ? 0x00000000 : 
				(unsigned long)(g * 255.f) << 8;

			unsigned long B = 
				(b > 1.f) ? 0x00FF0000 : 
				(b < 0.f) ? 0x00000000 : 
				(unsigned long)(b * 255.f) << 16;

			return (B | G | R);
		}

		inline unsigned long GetColorD3DMCOLOR()
		{
			unsigned long R = 
				(r > 1.f) ? 0x00FF0000 : 
				(r < 0.f) ? 0x00000000 : 
				(unsigned long)(r * 255.f) << 16;

			unsigned long G = 
				(g > 1.f) ? 0x00FF00 : 
				(g < 0.f) ? 0x000000 : 
				(unsigned long)(g * 255.f) << 8;

			unsigned long B = 
				(b > 1.f) ? 0x0000FF : 
				(b < 0.f) ? 0x000000 : 
				(unsigned long)(b * 255.f);

			return (0xFF000000 | R | G | B);
		}

		Color& operator = (YGC a_Color)
		{
			r = PixelGetRedRatio(a_Color);
			g = PixelGetGreenRatio(a_Color);
			b = PixelGetBlueRatio(a_Color);

			return *this;
		}

		Color& operator = (const Color& a_Other)
		{
			r = a_Other.r;
			g = a_Other.g;
			b = a_Other.b;
			return *this;
		}

		Color& operator = (float a_Scalar)
		{
			r = a_Scalar;
			g = a_Scalar;
			b = a_Scalar;
			return *this;
		}

		Color& operator += (const Color& a_Other)
		{
			r += a_Other.r;
			g += a_Other.g;
			b += a_Other.b;

			return *this;
		}
		Color& operator += (float a_Scalar)
		{
			r += a_Scalar;
			g += a_Scalar;
			b += a_Scalar;

			return *this;
		}
		Color& operator += (YGC a_Color)
		{
			Color temp(a_Color);
			*this += temp;
			return *this;
		}
		Color operator + (const Color& a_Other)
		{
			Color result(r, g, b);
			result += a_Other;
			return result;
		}
		Color operator + (float a_Scalar)
		{
			Color result(r, g, b);
			result += a_Scalar;
			return result;
		}


		Color& operator -= (const Color& a_Other)
		{
			r -= a_Other.r;
			g -= a_Other.g;
			b -= a_Other.b;

			return *this;
		}
		Color& operator -= (float a_Scalar)
		{
			r -= a_Scalar;
			g -= a_Scalar;
			b -= a_Scalar;

			return *this;
		}
		Color operator - (const Color& a_Other)
		{
			Color result(r, g, b);
			result -= a_Other;
			return result;
		}
		Color operator - (float a_Scalar)
		{
			Color result(r, g, b);
			result -= a_Scalar;
			return result;
		}


		Color& operator *= (const Color& a_Other)
		{
			r *= a_Other.r;
			g *= a_Other.g;
			b *= a_Other.b;
			
			return *this;
		}
		Color& operator *= (float a_Scalar)
		{
			r *= a_Scalar;
			g *= a_Scalar;
			b *= a_Scalar;
			
			return *this;
		}
		Color operator * (const Color& a_Other)
		{
			Color result(r, g, b);
			result *= a_Other;
			return result;
		}
		Color operator * (float a_Scalar)
		{
			Color result(r, g, b);
			result *= a_Scalar;
			return result;
		}


		Color& operator /= (const Color& a_Other)
		{
			r /= a_Other.r;
			g /= a_Other.g;
			b /= a_Other.b;
			
			return *this;
		}
		Color& operator /= (float a_Scalar)
		{
			r /= a_Scalar;
			g /= a_Scalar;
			b /= a_Scalar;
			
			return *this;
		}
		Color operator / (const Color& a_Other)
		{
			Color result(r, g, b);
			result /= a_Other;
			return result;
		}
		Color operator / (float a_Scalar)
		{
			Color result(r, g, b);
			result /= a_Scalar;
			return result;
		}

		bool operator != (Color& a_Other)
		{
			if (r == a_Other.r || g == a_Other.g || b == a_Other.b) { return false; }
			return true;
		}

		bool operator == (Color& a_Other)
		{
			if (r != a_Other.r || g != a_Other.g || b != a_Other.b) { return false; }
			return true;
		}

		inline Color& ClampUp(float a_Upper = 1.f)
		{
			r = (r > a_Upper) ? a_Upper : r;
			g = (g > a_Upper) ? a_Upper : g;
			b = (b > a_Upper) ? a_Upper : b;
			return *this;
		}

		inline Color& ClampDown(float a_Lower = 0.f)
		{
			r = (r < a_Lower) ? a_Lower : r;
			g = (g < a_Lower) ? a_Lower : g;
			b = (b < a_Lower) ? a_Lower : b;
			return *this;
		}

		inline Color& Clamp(float a_Lower = 0.f, float a_Upper = 1.f)
		{
			ClampDown(a_Lower);
			ClampUp(a_Upper);
			return *this;
		}

		// Public members

		float r, g, b;

		// Static methods

		static Color CNONE;
		static Color CBLACK;
		static Color CWHITE;
		static Color CRED;
		static Color CGREEN;
		static Color CBLUE;
		static Color CYELLOW;
		static Color CFUCHSIA;
		static Color CLIGHTBLUE;

		inline static Color RANDOM(float a_Min = 0.f, float a_Max = 1.f)
		{
			return
			(
				Color
				(
					Math::Random(a_Min, a_Max),
					Math::Random(a_Min, a_Max),
					Math::Random(a_Min, a_Max)
				)
			);
		}

	}; // class Color

}; // namespace YoghurtGum

#endif